//
// Created by wxd on 2025/7/15.
//

#pragma once

#include <glad/glad.h>
#include <string>
#include "BaseTexture.h"

class Texture : public BaseTexture {
public:

    /**
     * 纹理类型
     */
    enum class TextureType {
        TEXTURE_2D,
        TEXTURE_CUBE_MAP,
        TEXTURE_2D_ARRAY,
        TEXTURE_3D
    };

    /**
     * 纹理的包裹模式
     */
    enum class WrapMode {
        NONE,
        REPEAT = GL_REPEAT,
        MIRRORED_REPEAT = GL_MIRRORED_REPEAT,
        CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,
        CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER
    };

    /**
     * 纹理的过滤模式
     */
    enum class FilterMode {
        NEAREST = GL_NEAREST,
        LINEAR = GL_LINEAR,
        // Note: 如果默认没有开启mipmap的生成，使用下述参数会导致采样时寻找不存在的mipmap层级，从而找不到对应的纹理进行渲染
        NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST,
        LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST,
        NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR,
        LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR
    };

    /**
     * 纹理参数：filter + wrapper
     */
    struct TextureParams{
        bool mipmapGenerated;
        FilterMode minFilter, magFilter;
        WrapMode wrapS, wrapT, wrapR;

        TextureParams(const bool enableMipmap,
                      const FilterMode min, const FilterMode mag,
                      const WrapMode s, const WrapMode t, WrapMode r = WrapMode::NONE) :
            mipmapGenerated(enableMipmap), minFilter(min), magFilter(mag), wrapS(s), wrapT(t), wrapR(r) {}
    };

    Texture(const Texture&) = delete;
    Texture& operator=(const Texture&) = delete;
    ~Texture();

    // 默认参数构造，仅创建纹理单元
    explicit Texture(const TextureType textureType = TextureType::TEXTURE_2D) :
        m_TextureId(0), m_TextureUnit(0),
        m_TextureType(textureType),
        m_Width(0), m_Height(0), m_Channels(0),
        m_InternalFormat(GL_RGBA), m_Format(GL_RGBA),
        m_DataType(GL_UNSIGNED_BYTE),
        m_MinFilter(FilterMode::LINEAR_MIPMAP_LINEAR), m_MagFilter(FilterMode::LINEAR),
        m_WrapS(WrapMode::REPEAT), m_WrapT(WrapMode::REPEAT), m_WrapR(WrapMode::REPEAT),
        m_MipmapsGenerated(false) {

        glGenTextures(1, &m_TextureId);
    }

    // 默认参数构造，加载纹理并创建纹理单元 默认是0号单元
    Texture(const std::string& texturePath);
    Texture(const std::string& texturePath, bool useTest); // 测试用的默认构造
    Texture(const std::string& texturePath, int textureUnit);
    // 外部传递纹理参数的构造函数, 默认都是0号单元
    Texture(const std::string& texturePath, const TextureParams& params);
    Texture(const std::string& texturePath, const TextureParams& params, int textureUnit);
    // 外部传入纹理参数 + 激活的纹理单元 + 是否flip
    Texture(const std::string& texturePath, const TextureParams& params, int textureUnit, bool enableFlip);


    void setFilter(FilterMode minFilter, FilterMode magFilter);
    void setWrapper(WrapMode wrapS, WrapMode wrapT, WrapMode wrapR);

    void setSamplerName(const std::string& samplerName);

    void bind() const;
    void unbind() const;

    void generateMipmaps();

    int getTextureUnit() const;
    std::string getSamplerName() const;

private:

    GLuint m_TextureId;
    int m_TextureUnit;
    TextureType m_TextureType;
    int m_Width, m_Height, m_Channels;
    GLenum m_InternalFormat;
    GLenum m_Format;
    GLenum m_DataType;
    FilterMode m_MinFilter, m_MagFilter;
    WrapMode m_WrapS, m_WrapT, m_WrapR;
    bool m_MipmapsGenerated;

    std::string m_SamplerName;

    // 根据通道数确定格式
    void determineFormat(const int channels) {
        switch (channels) {
            case 1:
                m_Format = GL_RED;
                m_InternalFormat = GL_R8;
                break;
            case 2:
                m_Format = GL_RG;
                m_InternalFormat = GL_RG8;
                break;
            case 3:
                m_Format = GL_RGB;
                m_InternalFormat = GL_RGB8;
                break;
            case 4:
                m_Format = GL_RGBA;
                m_InternalFormat = GL_RGBA8;
                break;
            default:
                m_Format = GL_RGBA;
                m_InternalFormat = GL_RGBA8;
        }
    }

    // 设置纹理参数
    void setTextureParameters() {
        glTexParameteri(getGLTextureType(), GL_TEXTURE_MIN_FILTER, static_cast<GLint>(m_MinFilter));
        glTexParameteri(getGLTextureType(), GL_TEXTURE_MAG_FILTER, static_cast<GLint>(m_MagFilter));
        glTexParameteri(getGLTextureType(), GL_TEXTURE_WRAP_S, static_cast<GLint>(m_WrapS));
        glTexParameteri(getGLTextureType(), GL_TEXTURE_WRAP_T, static_cast<GLint>(m_WrapT));

        /**
         * m_WrapR 是程序自定义的环绕模式（如重复、镜像重复、边缘拉伸等），被转换为OpenGL枚举值
         */
        if (m_TextureType == TextureType::TEXTURE_CUBE_MAP || m_TextureType == TextureType::TEXTURE_3D) {
            glTexParameteri(getGLTextureType(), GL_TEXTURE_WRAP_R, static_cast<GLint>(m_WrapR));
        }
    }

    // 获取纹理类型
    GLenum getGLTextureType() const {
        switch (m_TextureType) {
            case TextureType::TEXTURE_2D: return GL_TEXTURE_2D;
            case TextureType::TEXTURE_CUBE_MAP: return GL_TEXTURE_CUBE_MAP;
            case TextureType::TEXTURE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
            case TextureType::TEXTURE_3D: return GL_TEXTURE_3D;
            default: return GL_TEXTURE_2D;
        }
    }

    void initDefaultTextureParams() {
        m_TextureId = 0,
        m_TextureUnit = 0,
        m_TextureType = TextureType::TEXTURE_2D,
        m_Width = 0, m_Height = 0, m_Channels = 0,
        m_InternalFormat = GL_RGBA, m_Format = GL_RGBA,
        m_DataType = GL_UNSIGNED_BYTE,
        m_MinFilter = FilterMode::LINEAR_MIPMAP_LINEAR,
        m_MagFilter = FilterMode::LINEAR,
        m_WrapS = WrapMode::REPEAT,
        m_WrapT = WrapMode::REPEAT,
        m_WrapR = WrapMode::REPEAT,
        m_MipmapsGenerated = false;
    }
};